package com.misoneism.fire.util
{
	import flash.utils.describeType;

	/**
	 * Provides a generic enum handler for ActionScript. Automagically sets
	 * a private variable with the name of the Enum's constant, for debugging
	 * purposes.
	 * 
	 * It is based on this blog post: http://scottbilas.com/2008/12/16/update-2-faking-enums-in-as3/
	 * 
	 * @example An example of the Enum's use:
	 * <listing version="3.0"> 
	 * class AnEnum extends Enum
	 * {
	 *		public static const VALUE_A: AnEnum = new AnEnum(  );
	 *		public static const VALUE_B: AnEnum = new AnEnum(  );
	 *
	 * 		{ initEnum( AnEnum ) }
	 * }
	 * </listing>
	 */
	public class Enum
	{
		/**
		 * Get the constant name of the enum.
		 */
		public function get name(  ): String
		{
			return _name;
		}
		
		
		/**
		 * Override the label generation for the enum
		 */
	    public function toString(  ): String
		{
			return name;
		}
		
		
		/**
		 * Converts the <code>name</code> into a display string by converting
		 * underscores to spaces and changing the name to sentence case.
		 * 
		 * <p>eg. MY_ENUM --> "My enum"</p>
		 * 
		 * <p>Note: using this function is NOT suitable for multilingual applications.</p>
		 */
		public function displayName(  ): String
		{
			// underscores -> spaces
			var transformName: String = _name.replace( /_/g, " " );
			
			// change all letters to lower case.
			transformName = transformName.toLocaleLowerCase(  );
			
			// change first letter to upper case.
			transformName = transformName.charAt( 0 ).toLocaleUpperCase(  ) + transformName.substr( 1 );
			
			return transformName;
		}
		
		
		/**
		 * Initialise the enum's constant naming. This iterates over all internal
		 * constants, setting their names for run time interrogation. 
		 */
	    protected static function initEnum( enum: Class ): void
	    {
	        var type: XML = flash.utils.describeType( enum );
	        
	        for each ( var constant: XML in type.constant )
	        {
	        	if ( enum[ constant.@name ] is Enum )
	        	{
		            var enumConstant: Enum = enum[ constant.@name ];
		
		            if ( enumConstant.name != null )
		            {
		                throw new Error( "Can't initialise '" + enum + "' twice." );
		            }
		
		            if ( enumConstant[ "constructor" ] != enum )
		            {
		                throw new Error( "Constant type '" + enumConstant[ "constructor" ] + "' " +
		                    "does not match its enum class '" + enum + "'." );
		            }
		
		            enumConstant._name = constant.@name;
		        }
	        }
	    }
	    
	    
	    /**
	    * Holds the user defined, declared enumerator variable name
	    * as a local string.  eg. if an <code>Enum</code> was declared
	    * as MY_ENUM, then <code>_name</code> would be "MY_ENUM".
	    */
		private var _name: String = null;
	}
}